﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

using Swaf;
using Swaf.BizObj;
using Swaf.BizRule;

namespace PageEditing
{
	public class MenuEditorBizRules : Syrinx.BaseBizRules
	{
		public IBizObjList getMenuTypes(IApplication app, IRuleContext context)
		{
			IBizObjList menuTypes = app.appData.get("SiteMenuTypes") as IBizObjList;
			return menuTypes;
		}

		static string s_cmpSettingsStartoff = "$CmpSetting(sitePath)$/";
		static Regex s_menuStart = new Regex(@"\s*<div\s+runat=""server""\s*id=""([^""]+)""\s*class=""\w+Menu-Inner""[^>]*>");
		static Regex s_menuItem = new Regex(@"(?:<%if\(SyrinxPage.currentPrincipalPrivilege\(""AppFunctions\.([^""]+)""\)[^\)]+\)\{%>)?<div\s+class=""MenuItem(?:\s+[^""]*)?""><asp:HyperLink\s+runat=""server""\s+(?:target=""([^""]*)""\s+)?NavigateUrl=""([^""]*)""><swf:DivLayers\s+runat=""server""\s+SkinID=""[^""]+""><asp:Label\s+runat=""server""\s+ID=""[^""]+"">([^<]*)</asp:Label></swf:DivLayers></asp:HyperLink></div>", RegexOptions.IgnoreCase);
		static Regex s_menuCheckCode = new Regex(@"//Page menu check area(.+?)//End page menu check area", RegexOptions.Singleline);
		static Regex s_ifBlocks = new Regex(@"if\((?:vn.(?:CompareTo|StartsWith)\(""([^""]+)""\).*?(?:\|\|)?\s*)+\)\s*mainMenu = ([^;]+);");
		public IBizObj getMenuDetailsForEditing(IApplication app, IRuleContext context, string menuType)
		{
			IBizObj menuCtl = app.bizObjMgr.create("SiteMenuControl");
			menuCtl.put("menuType", menuType);

			string baseDir = PageEditBizRules.getBaseDir(app, true);
			string menuName = Cmn.pathCombine(baseDir, "SiteControls", menuType + ".ascx");

			if(File.Exists(menuName))
			{
				MatchCollection mc;
				IBizObjList menus = (IBizObjList)menuCtl.get("menus");
				IBizObj menu = null;
				string ctlContents = File.ReadAllText(menuName);

				mc = s_menuStart.Matches(ctlContents);
				int nextKey = 0;
				foreach(Match m in mc)
				{
					menu = menus.insertNew();
					menu.put("id", nextKey++);
					menu.put("name", m.Groups[1].Value);
					menu.put("startPos", m.Index);
					menu.isNew = false;
					menu.clearDirtyFlags();
				}
				if (menus.numElements > 0)
				{
					mc = s_menuItem.Matches(ctlContents);
					int curMenuPos = 1;
					menu = menus[0];
					IBizObjList menuItems = (IBizObjList)menu.get("menuItems");
					foreach (Match m in mc)
					{
						if (curMenuPos < menus.numElements && m.Index > (int)menus[curMenuPos].get("startPos"))
						{
							menu = menus[curMenuPos++];
							menuItems = (IBizObjList)menu.get("menuItems");
						}

						IBizObj menuItem = menuItems.insertNew();
						menuItem.put("id", menuItems.numElements -1);
						string url = m.Groups[3].Value;
						if (url.StartsWith(s_cmpSettingsStartoff))
							url = url.Substring(s_cmpSettingsStartoff.Length);
						menuItem.put("url", url);
						menuItem.put("displayName", m.Groups[4].Value);
						bool reuseWindow = true;
						if (m.Groups[2].Value.Length != 0)
							reuseWindow = false;
						menuItem.put("reuseWindow", reuseWindow);
						menuItem.put("securityAppFunction", m.Groups[1].Value);

						menuItem.isNew = false;
						menuItem.clearDirtyFlags();
					}

					Match m2 = s_menuCheckCode.Match(ctlContents);
					if (m2.Success)
					{
						mc = s_ifBlocks.Matches(m2.Groups[1].Value);
						foreach (Match m3 in mc)
						{
							menuName = m3.Groups[2].Value;
							menu = menus.search("name", menuName);
							if (menu != null)
							{
								StringBuilder buff = new StringBuilder(200);
								foreach (Capture c2 in m3.Groups[1].Captures)
									buff.Append(c2.Value).Append(",");
								menu.put("pagesAppliedTo", buff.ToString(0, buff.Length - 1));
							}
						}
					}
				}

			}

			menuCtl.isNew = false;
			menuCtl.clearDirtyFlags();
			return menuCtl;
		}

		protected static Regex s_endDiv = new Regex(@"^\s*</div>\r?$", RegexOptions.Multiline);

		public void updateMenuForEditing(IApplication app, IRuleContext context, IBizObj menuInfo)
		{		
			string menuType = (string)menuInfo.get("menuType");	
			string baseMenuType = menuType.CompareTo("MainMenu")==0?"":menuType.EndsWith("Menu")?menuType.Substring(0, menuType.Length - 4):menuType;
			string baseDir = PageEditBizRules.getBaseDir(app, true);
			string menuName = Cmn.pathCombine(baseDir, "SiteControls", menuType + ".ascx");

			if(File.Exists(menuName))
			{
				string ctlContents = File.ReadAllText(menuName);
				StringBuilder newContents = new StringBuilder(ctlContents.Length + 1024);
				int nextReadPos = 0;
				IBizObjList menus = (IBizObjList)menuInfo.get("menus");
				//Update code that switches which menu to show
				Match m2 = s_menuCheckCode.Match(ctlContents);
				if (m2.Success)
				{
					newContents.Append(ctlContents.Substring(nextReadPos, m2.Index - nextReadPos));
					newContents.AppendLine("//Page menu check area");
					nextReadPos = m2.Index + m2.Length;
					bool onFirst = true;
					foreach (IBizObj menu in menus)
					{
						string pagesAppliedTo = (string)menu.get("pagesAppliedTo");
						if (!Cmn.IsEmpty(pagesAppliedTo))
						{
							if(onFirst)
								newContents.Append("		if(");
							else
								newContents.Append("		else if(");
							onFirst = false;
							string[] pageNames = pagesAppliedTo.Split(',');
							for(int pos = 0; pos < pageNames.Length; ++pos)
							{
								string pageName = pageNames[pos];
								if(pageName.EndsWith("/"))
									newContents.Append("vn.StartsWith(\"").Append(pageName).Append("\")");
								else
									newContents.Append("vn.CompareTo(\"").Append(pageName).Append("\")== 0");
								if (pos < pageNames.Length - 1)
									newContents.Append(" || ");
							}
							newContents.AppendLine(")");
							newContents.Append("			mainMenu = ");
							newContents.Append(menu.get("name")).AppendLine(";");
						}
					}
					newContents.AppendLine("		//End page menu check area");
				}
				
				MatchCollection mc = s_menuStart.Matches(ctlContents);
				if(mc.Count > 0)
				{
					IBizObj firstMenu = menus[0];
					int startPos = mc[0].Index;
					int endPos = mc[mc.Count-1].Index + mc[mc.Count-1].Length +1;
					Match m = s_endDiv.Match(ctlContents, endPos);

					if(m.Success)
						endPos = m.Index + m.Length;
						
					newContents.Append(ctlContents.Substring(nextReadPos,startPos-nextReadPos));
					int menuNum = 0;
					int menuItemNum = 0;
					foreach(IBizObj menu in menus)
					{
						string childMenuName = (string)menu.get("name");
						if (childMenuName == null)
							throw new BaseException("Unexpected null for menuName in updateMenuForEditing");
						childMenuName = childMenuName.Replace(" ", "");
						newContents.AppendFormat("	<div runat=\"server\" id=\"{0}\" class=\"{1}-Inner\" visible=\"false\">\r\n", childMenuName, menuType);
						IBizObjList menuItems = (IBizObjList)menu.get("menuItems");
						int numItems = menuItems.numElements;
						for(int pos = 0; pos < numItems; pos++)
						{
							IBizObj menuItem = menuItems[pos];
							string target = "";
							if (!(bool)menuItem.get("reuseWindow"))
								target = "Target=\"_blank\"";
							string url = (string)menuItem.get("url");
							if (!url.Contains(":") && !url.StartsWith(s_cmpSettingsStartoff))
								url = s_cmpSettingsStartoff + url;
							bool hasSecurity = !Cmn.IsEmpty(menuItem.get("securityAppFunction"));
							if (hasSecurity)
								newContents.AppendFormat("		<%if(SyrinxPage.currentPrincipalPrivilege(\"AppFunctions.{0}\") >= Swaf.Security.Privileges.ReadOnly){{%>", menuItem.get("securityAppFunction"));

							string extraCssClass = pos == 0?" FirstChild":pos == numItems-1?" LastChild":"";
							newContents.AppendFormat("{5}<div class=\"MenuItem{7}\"><asp:HyperLink runat=\"server\" {4} NavigateUrl=\"{0}\"><swf:DivLayers runat=\"server\" SkinID=\"{6}UnselectedMenu\"><asp:Label runat=\"server\" ID=\"_m{2}n{3}\">{1}</asp:Label></swf:DivLayers></asp:HyperLink></div>\r\n",
								url, menuItem.get("displayName"), menuNum, menuItemNum++, target, hasSecurity?"":"		", baseMenuType,
								extraCssClass);
							if (hasSecurity)
								newContents.Append("<%}%>");
						}
						newContents.Append("	</div>\r\n");
						menuNum++;
					}
					newContents.Append(ctlContents.Substring(endPos));
					File.WriteAllText(menuName, newContents.ToString());
				}
			}
			
		}
	}
}
